今天來實作一個圖片編輯常用的功能: 拼貼。
顧名思義就是能把自己圖片拼到已經設定好的框框中,而圖片可以在框框中調整要顯示的部分,也就是固定位置的裁切功能。
配合之前練習的拖拉圖片進入 canvas
來做到讓使用者自行上傳圖片,再將圖片拖曳進去 canvas
拼貼。
拖曳部分相關可參考 Day 18 - Fabricjs 實作: 圖片上傳並透過拖曳進入 canvas
這邊就不在重複解釋了
我的作法是想要直接讓之後設定的 clipPath
直接依據一開始所設定好的 Layout 做裁切。
首先先建出虛線矩形區塊讓使用者填入,並且將 selectable
設定為 false
,只是要讓使用者觀看框框的範圍,所以就不需要讓使用者移動。
自訂 isClipFrame
屬性之後用配合 drop 事件,判斷使用者拖曳到的是不是我們設定的虛線框。
let clipPathTop = new fabric.Rect({
// ...略
fill: 'transparent',
selectable: false,
isClipFrame: true
})
let clipPathBottom = new fabric.Rect({
width: 490,
height:240,
left: 5,
top: 255,
stroke: 'red',
strokeWidth: 1,
strokeDashArray: [5, 5],
fill: 'transparent',
selectable: false,
isClipFrame: true
})
canvas.add(clipPathTop)
canvas.add(clipPathBottom)
拖拉 Drap & drop 請參考 Day 18 - Fabricjs 實作: 圖片上傳並透過拖曳進入 canvas
這邊要做的動作分幾個步驟
target
是否為矩形虛線框target
。這邊可以做到這個功能,主要是靠 absolutePositioned
這個屬性,只要將裁切遮罩中的這屬性設成 true
,此物件這時候 left
、top
屬性和一般裁切不同的地方在於此物件起始會回到 (0,0),而不是被裁切物件中心。
你可以想像成在 canvas
上挖洞固定在某個位置,而只有那個位置能夠顯示被裁切的物件。
這邊因為要做出裁切效果,之後為了更好擴充我們不直接寫死,改成複製一份目標框物件,再將複製出來的 absolutePositioned
屬性設定成 true
。
target.clone(cloned => clipPath = cloned)
clipPath.absolutePositioned = true
這邊做的事情是比對原始圖片和框的大小是否適合,做出相對應的大小調整動作。
最後固定一軸的移動 X or Y
,讓使用者對齊自行調整。
// 判斷長寬是否為滿版來做調整並鎖定 X Y
image.scaleToWidth(target.width)
const isFullHeight = image.getScaledHeight() < target.height
if (isFullHeight) image.scaleToHeight(target.height)
image.lockMovementY = isFullHeight
image.lockMovementX = !isFullHeight
完整函數拼貼動作函數
function dropImg (e) {
let target = e.target
if (!target.isClipFrame) return
// 設定匯入圖塊
target.clone(cloned => clipPath = cloned)
clipPath.absolutePositioned = true
const image = new fabric.Image(movingImage, {
width: movingImage.naturalWidth,
height: movingImage.naturalHeight,
left: target.left,
top: target.top,
clipPath,
})
// 判斷長寬是否為滿版來做調整並鎖定 X Y
image.scaleToWidth(target.width)
const isFullHeight = image.getScaledHeight() < target.height
if (isFullHeight) image.scaleToHeight(target.height)
image.lockMovementY = isFullHeight
image.lockMovementX = !isFullHeight
image.clipPath = clipPath
canvas.add(image)
}
檔案上傳部分相關可參考 Day 18 - Fabricjs 實作: 圖片上傳並透過拖曳進入 canvas
因為我們是直接寫成複製虛線框物件來做裁切,這樣一來,我們就能夠更方便的拼貼圖片,只要我們先將預設的虛線框建出來就可以了!
任何形狀都能裁切!
接下來將預設好的 Layout 儲存起來,包成函數讓使用者可以透過按鈕來切換預設 Layout 。
也能夠直接使用 SVG 來當作裁切的框,這樣一來可以做的變化就更多了!
function setLayoutStyle3 () {
canvas.clear()
const URL = 'https://upload.wikimedia.org/wikipedia/commons/4/42/Love_Heart_SVG.svg'
fabric.loadSVGFromURL(URL, (objects, options) => {
console.log(options)
let svgClip = fabric.util.groupSVGElements(objects, options)
svgClip.scaleToWidth(300)
svgClip.set({
left: 100,
top: 100,
stroke: 'red',
strokeWidth: 1,
strokeDashArray: [5, 5],
fill: 'transparent',
selectable: false,
isClipFrame: true,
})
canvas.add(new fabric.Rect({
...
}))
canvas.add(new fabric.Rect({
...
}))
canvas.add(svgClip).renderAll()
})
}
svg form Wikimedia Commons
利用設定 absolutePositioned
固定畫布上的裁切位置。
並且基於這個方式實作出簡易拼貼圖片功能。
利用 SVG 做出更豐富的裁切框。